/*
 *  +----------------------------------------------------------------------
 *  | sophon [ A FAST GAME FRAMEWORK ]
 *  +----------------------------------------------------------------------
 *  | Copyright (c) 2023-2029 All rights reserved.
 *  +----------------------------------------------------------------------
 *  | Licensed ( http:www.apache.org/licenses/LICENSE-2.0 )
 *  +----------------------------------------------------------------------
 *  | Author: jqiris <1920624985@qq.com>
 *  +----------------------------------------------------------------------
 */

use std::sync::Arc;
use std::time::Duration;

use async_trait::*;
use dashmap::DashMap;
use etcd_client::*;
use once_cell::sync::OnceCell;
use tokio::sync::RwLock;

pub use etcd::*;
pub use filter::*;
pub use finder::*;

use crate::{configs::*, errors::DiscoverError, logger::*, treaty::*};
use crate::{error, fatal, info};

mod etcd;
mod filter;
mod finder;

const DEFAULT_SERVER_PREFIX: &str = "/server/";
const DEFAULT_DATA_PREFIX: &str = "/data/";

type Discoverer = Arc<RwLock<dyn IDiscoverer + Sync + Send>>;

static DEF_DISCOVERER: OnceCell<Discoverer> = OnceCell::new();

pub async fn init_discoverer(cfg: DiscoverConf) {
    if &cfg.use_type != "etcd" {
        return;
    }
    let options = EtcdOptions::new()
        .with_timeout(Duration::from_secs(cfg.dial_timeout))
        .with_server_prefix(cfg.server_prefix)
        .with_data_prefix(cfg.data_prefix)
        .build();

    let server = EtcdDiscoverer::new(cfg.endpoints, options).await;
    let ds = Arc::new(RwLock::new(server));
    if let Err(_) = DEF_DISCOVERER.set(ds.clone()) {
        fatal!("init_discoverer err");
    }
}

//global function
pub fn global_discover() -> &'static Discoverer {
    DEF_DISCOVERER.get().expect("discoverer is not initialized")
}

pub async fn register(server: &Server) -> Result<(), DiscoverError> {
    let mut ds = global_discover().write().await;
    ds.register(server).await
}

pub async fn un_register(server: &Server) -> Result<(), DiscoverError> {
    let mut ds = global_discover().write().await;
    ds.un_register(server).await
}

pub async fn get_server_list(
    options: Option<Vec<FilterOption>>,
) -> Option<DashMap<String, Server>> {
    let ds = global_discover().read().await;
    ds.get_server_list(options)
}

pub async fn get_server_by_id(
    server_id: &str,
    options: Option<Vec<FilterOption>>,
) -> Option<Server> {
    let ds = global_discover().read().await;
    ds.get_server_by_id(server_id, options)
}

pub async fn get_server_by_type(
    server_type: &str,
    server_arg: &str,
    options: Option<Vec<FilterOption>>,
) -> Option<Server> {
    let ds = global_discover().read().await;
    ds.get_server_by_type(server_type, server_arg, options)
}

pub async fn get_server_by_type_load(
    server_type: &str,
    options: Option<Vec<FilterOption>>,
) -> Option<Server> {
    let ds = global_discover().read().await;
    ds.get_server_by_type_load(server_type, options)
}

pub async fn get_server_type_list(
    server_type: &str,
    options: Option<Vec<FilterOption>>,
) -> Option<DashMap<String, Server>> {
    let ds = global_discover().read().await;
    ds.get_server_type_list(server_type, options)
}

pub async fn register_server_event_handlers(handlers: &mut Vec<ServerHander>) {
    let mut ds = global_discover().write().await;
    ds.register_server_event_handlers(handlers).await;
}

pub async fn register_data_event_handlers(handlers: &mut Vec<DataHander>) {
    let mut ds = global_discover().write().await;
    ds.register_data_event_handlers(handlers);
}

pub async fn incre_load(
    server_id: &str,
    load: i64,
    options: Option<Vec<FilterOption>>,
) -> Option<DiscoverError> {
    let mut ds = global_discover().write().await;
    ds.incre_load(server_id, load, options).await
}

pub async fn decre_load(
    server_id: &str,
    load: i64,
    options: Option<Vec<FilterOption>>,
) -> Option<DiscoverError> {
    let mut ds = global_discover().write().await;
    ds.decre_load(server_id, load, options).await
}

pub async fn put_data(key: String, value: String) -> Option<DiscoverError> {
    let mut ds = global_discover().write().await;
    ds.put_data(key, value).await
}

pub async fn remove_data(key: &str) -> Option<DiscoverError> {
    let mut ds = global_discover().write().await;
    ds.remove_data(key).await
}

pub async fn get_data(key: &str) -> Result<String, DiscoverError> {
    let mut ds = global_discover().write().await;
    ds.get_data(key).await
}

pub async fn init_server_list() {
    let ds = global_discover().read().await;
    ds.init_server_list().await;
}

pub async fn get_server_steam() -> Result<WatchStream, DiscoverError> {
    let ds = global_discover().read().await;
    ds.get_server_steam().await
}

pub async fn deal_server_stream(resp: WatchResponse) {
    let ds = global_discover().read().await;
    ds.deal_server_stream(resp).await
}

pub async fn get_data_steam() -> Result<WatchStream, DiscoverError> {
    let ds = global_discover().read().await;
    ds.get_data_steam().await
}

pub async fn deal_data_stream(resp: WatchResponse) {
    let ds = global_discover().read().await;
    ds.deal_data_stream(resp).await
}

//定义接口
pub trait ServerEventHandler {
    fn server_event_handle(&self, event_type: &EventType, server: &Server);
}

pub trait DataEventHandler {
    fn data_event_handle(&self, kv: &KeyValue);
}

pub type ServerHander = Arc<dyn ServerEventHandler + Send + Sync>;
pub type DataHander = Box<dyn DataEventHandler + Send + Sync>;

#[async_trait]
pub trait IDiscoverer {
    async fn get_server_steam(&self) -> Result<WatchStream, DiscoverError>;
    async fn deal_server_stream(&self, resp: WatchResponse);
    async fn get_data_steam(&self) -> Result<WatchStream, DiscoverError>;
    async fn deal_data_stream(&self, resp: WatchResponse);
    async fn init_server_list(&self);
    async fn register(&mut self, server: &Server) -> Result<(), DiscoverError>;
    async fn un_register(&mut self, server: &Server) -> Result<(), DiscoverError>;
    fn get_server_list(
        &self,
        options: Option<Vec<FilterOption>>,
    ) -> Option<DashMap<String, Server>>;
    fn get_server_by_id(
        &self,
        server_id: &str,
        options: Option<Vec<FilterOption>>,
    ) -> Option<Server>;
    fn get_server_by_type(
        &self,
        server_type: &str,
        server_arg: &str,
        options: Option<Vec<FilterOption>>,
    ) -> Option<Server>;
    fn get_server_by_type_load(
        &self,
        server_type: &str,
        options: Option<Vec<FilterOption>>,
    ) -> Option<Server>;
    fn get_server_type_list(
        &self,
        server_type: &str,
        options: Option<Vec<FilterOption>>,
    ) -> Option<DashMap<String, Server>>;
    async fn register_server_event_handlers(&mut self, handlers: &mut Vec<ServerHander>);
    async fn apply_server_event_handlers(&self, event_type: &EventType, server: &Server);
    fn register_data_event_handlers(&mut self, handlers: &mut Vec<DataHander>);
    fn apply_data_event_handlers(&self, kv: &KeyValue);
    async fn incre_load(
        &mut self,
        server_id: &str,
        load: i64,
        options: Option<Vec<FilterOption>>,
    ) -> Option<DiscoverError>;
    async fn decre_load(
        &mut self,
        server_id: &str,
        load: i64,
        options: Option<Vec<FilterOption>>,
    ) -> Option<DiscoverError>;
    async fn put_data(&mut self, key: String, value: String) -> Option<DiscoverError>;
    async fn remove_data(&mut self, key: &str) -> Option<DiscoverError>;
    async fn get_data(&mut self, key: &str) -> Result<String, DiscoverError>;
}
